/**
 * 矩阵键盘:
 * 在键盘中按键数量较多时，为了减少I/O口的占用，通常将按键排列成矩阵形式
 * 采用逐行或逐列的“扫描”，就可以读出任何位置按键的状态
 * 
 * P17 连接 S1,  S2,  S3,  S4 的左端
 * P16 连接 S5,  S6,  S7,  S8 的左端
 * P15 连接 S9,  S10, S11, S12 的左端
 * P14 连接 S13, S14, S15, S16 的左端
 * 
 * P13 连接 S1,  S5,  S9,   S13 的右端
 * P12 连接 S2,  S6,  S10,  S14 的右端
 * P11 连接 S3,  S7,  S11,  S15 的右端
 * P10 连接 S4,  S8,  S12,  S16 的右端
 * 
 * 板子问题:
 * ∵P15 引脚还连接了"五线四项步进电机", 步进电机又连接了"蜂鸣器", ∴键盘"逐行扫描"时, 蜂鸣器会响, 关不掉.
 * ∴使用"逐列扫描"
 * 
 * 高电平引脚: 1, 若上拉, 接低电平=0
 * 低电平引脚: 0, 强下拉, 驱动能力强, 接高电平时, 能把高电平拉下来
 * 所以IO口, 能输入/输出
 * 见"STC89C52.pdf": 第4章 STC89C52系列单片机的I/O口结构
 */
#include <REGX52.H>
#include "Delay_Utils.h"

//行线
//  int rows[] = {P1_7, P1_6, P1_5, P1_4};  //这样定义会报错...
//  sbit rows[] = {P1^7, P1^6, P1^5, P1^4};  //这样定义会报错...
//  int rows[] = {0x97, 0x96, 0x95, 0x94};     //这样定义也没意义, 因为元素只是一些数字而已, 不是IO口
//列线
//   code columns[] = {P1_3, P1_2, P1_1, P1_0};    

/**
 * 获得矩阵键盘的按键, 按下时会一直停留在此函数, 松开才返回按键的值
 * 1.逐个按键扫描
 * 2.P1口整体赋值, 整体读取判断(见视频第47分钟)
 * @param isTx1C 是否是TX-1C板
 * @return 按下: 1~16, 未按下: 0
 */
unsigned char Matrix_Keyboard_Down_Delay(bit isTx1C) {
    if (isTx1C) {
        /**
         * 1.TX-1C, 先按列扫描, 不行, 整个液晶屏幕都是乱码
         */
        // P3 = 0xFF;//先全部置1
        //第1列=0
        // P3_4 = 0;//S1    按下消抖        等待按键松开      弹起消抖
        // if (P3_0 == 0) {DelayShake(); while (P3_0 == 0); DelayShake(); return 1;}
        // if (P3_1 == 0) {DelayShake(); while (P3_1 == 0); DelayShake(); return 5;}
        // if (P3_2 == 0) {DelayShake(); while (P3_2 == 0); DelayShake(); return 8;}
        // if (P3_3 == 0) {DelayShake(); while (P3_3 == 0); DelayShake(); return 4;}
        // //第2列=0
        // P3 = 0xFF; //TODO 能否不全置1, 而替换成: P3_3 = 0; ??????
        // P3_5 = 0;
        // if (P3_0 == 0) {DelayShake(); while (P3_0 == 0); DelayShake(); return 2;}
        // if (P3_1 == 0) {DelayShake(); while (P3_1 == 0); DelayShake(); return 6;}
        // if (P3_2 == 0) {DelayShake(); while (P3_2 == 0); DelayShake(); return 10;}
        // if (P3_3 == 0) {DelayShake(); while (P3_3 == 0); DelayShake(); return 8;}
        // //第3列=0
        // P3 = 0xFF; //TODO 能否不全置1, 而替换成: P3_3 = 0; ??????
        // P3_6 = 0;
        // if (P3_0 == 0) {DelayShake(); while (P3_0 == 0); DelayShake(); return 3;}
        // if (P3_1 == 0) {DelayShake(); while (P3_1 == 0); DelayShake(); return 10;}
        // if (P3_2 == 0) {DelayShake(); while (P3_2 == 0); DelayShake(); return 11;}
        // if (P3_3 == 0) {DelayShake(); while (P3_3 == 0); DelayShake(); return 12;}
        // //第4列=0
        // P3 = 0xFF; //TODO 能否不全置1, 而替换成: P3_3 = 0; ??????
        // P3_7 = 0;
        // if (P3_0 == 0) {DelayShake(); while (P3_0 == 0); DelayShake(); return 13;}
        // if (P3_1 == 0) {DelayShake(); while (P3_1 == 0); DelayShake(); return 14;}
        // if (P3_2 == 0) {DelayShake(); while (P3_2 == 0); DelayShake(); return 15;}
        // if (P3_3 == 0) {DelayShake(); while (P3_3 == 0); DelayShake(); return 16;}


        /**
         * 2.TX-1C, 先按行扫描, 不行
         *   1.只是扫描, 当按第1列按键时, 即使不调用液晶显示数字, 也会有问题
         *   2.         当按第1列按键时, if调用液晶显示数字, 也会有问题(显示长度有问题)
         */
        // P3 = 0xFF;//先全部置1
        //第1行=0
        // P3_0 = 0;//S1    按下消抖        等待按键松开      弹起消抖
        // if (P3_4 == 0) {DelayShake(); while (P3_4 == 0); DelayShake(); return 1;}
        // if (P3_5 == 0) {DelayShake(); while (P3_5 == 0); DelayShake(); return 2;}
        // if (P3_6 == 0) {DelayShake(); while (P3_6 == 0); DelayShake(); return 3;}
        // if (P3_7 == 0) {DelayShake(); while (P3_7 == 0); DelayShake(); return 4;}
        // //第2行=0
        // P3 = 0xFF; //TODO 能否不全置1, 而替换成: P3_3 = 0; ??????
        // P3_1 = 0;
        // if (P3_4 == 0) {DelayShake(); while (P3_4 == 0); DelayShake(); return 5;}
        // if (P3_5 == 0) {DelayShake(); while (P3_5 == 0); DelayShake(); return 6;}
        // if (P3_6 == 0) {DelayShake(); while (P3_6 == 0); DelayShake(); return 7;}
        // if (P3_7 == 0) {DelayShake(); while (P3_7 == 0); DelayShake(); return 8;}
        // //第3行=0
        // P3 = 0xFF; //TODO 能否不全置1, 而替换成: P3_3 = 0; ??????
        // P3_2 = 0;
        // if (P3_4 == 0) {DelayShake(); while (P3_4 == 0); DelayShake(); return 9;}
        // if (P3_5 == 0) {DelayShake(); while (P3_5 == 0); DelayShake(); return 10;}
        // if (P3_6 == 0) {DelayShake(); while (P3_6 == 0); DelayShake(); return 11;}
        // if (P3_7 == 0) {DelayShake(); while (P3_7 == 0); DelayShake(); return 12;}
        // //第4行=0
        // P3 = 0xFF; //TODO 能否不全置1, 而替换成: P3_3 = 0; ??????
        // P3_3 = 0;
        // if (P3_4 == 0) {DelayShake(); while (P3_4 == 0); DelayShake(); return 13;}
        // if (P3_5 == 0) {DelayShake(); while (P3_5 == 0); DelayShake(); return 14;}
        // if (P3_6 == 0) {DelayShake(); while (P3_6 == 0); DelayShake(); return 15;}
        // if (P3_7 == 0) {DelayShake(); while (P3_7 == 0); DelayShake(); return 16;}


        /**
         * 3.整体赋值, 然后整体读取
         *   问题和上方一致
         */
        unsigned char temp, key;
        P3 = 0xFE;//给 P3.0 送低电平，其余为高电平
        temp = P3 & 0xF0;
        if (temp != 0xF0) {
            DelayShake();
            if (temp != 0xF0) { //如果还是按下状态
                if (P3 == 0xEE) key = 1; if (P3 == 0xDE) key = 2; if (P3 == 0xBE) key = 3; if (P3 == 0x7E) key = 4;
                while (temp != 0xF0) temp = P3 & 0xF0;  //如果没有释放就一直等待并且, TODO 可否直接判断P3?
                return key;
            }
        }
        P3 = 0xFD;//给 P3.1 送低电平，其余为高电平
        temp = P3 & 0xF0;
        if (temp != 0xF0) {
            DelayShake();
            if (temp != 0xF0) { //如果还是按下状态
                if (P3 == 0xED) key = 5; if (P3 == 0xDD) key = 6; if (P3 == 0xBD) key = 7; if (P3 == 0x7D) key = 8;
                while (temp != 0xF0) temp = P3 & 0xF0;
                return key;
            }
        }
        P3 = 0xFB;//给 P3.2 送低电平，其余为高电平
        temp = P3 & 0xF0;
        if (temp != 0xF0) {
            DelayShake();
            if (temp != 0xF0) { //如果还是按下状态
                if (P3 == 0xEB) key = 9; if (P3 == 0xDB) key = 10; if (P3 == 0xBB) key = 11; if (P3 == 0x7B) key = 12;
                while (temp != 0xF0) temp = P3 & 0xF0;
                return key;
            }
        }
        P3 = 0xF7;//给 P3.3 送低电平，其余为高电平
        temp = P3 & 0xF0;
        if (temp != 0xF0) {
            DelayShake();
            if (temp != 0xF0) { //如果还是按下状态
                if (P3 == 0xE7) key = 13; if (P3 == 0xD7) key = 14; if (P3 == 0xB7) key = 15; if (P3 == 0x77) key = 16;
                while (temp != 0xF0) temp = P3 & 0xF0;
                return key;
            }
        }
        return 0;
    }
    
    //下方是视频讲解的代码
    P1 = 0xFF;//先全部置1
    //第1列=0
    P1_3 = 0;//S1    按下消抖        等待按键松开      弹起消抖
    if (P1_7 == 0) {DelayShake(); while (P1_7 == 0); DelayShake(); return 1;}
    if (P1_6 == 0) {DelayShake(); while (P1_6 == 0); DelayShake(); return 5;}
    if (P1_5 == 0) {DelayShake(); while (P1_5 == 0); DelayShake(); return 9;}
    if (P1_4 == 0) {DelayShake(); while (P1_4 == 0); DelayShake(); return 13;}
    //第2列=0
    P1 = 0xFF; //TODO 能否不全置1, 而替换成: P1_3 = 0; ??????
    P1_2 = 0;
    if (P1_7 == 0) {DelayShake(); while (P1_7 == 0); DelayShake(); return 2;}
    if (P1_6 == 0) {DelayShake(); while (P1_6 == 0); DelayShake(); return 6;}
    if (P1_5 == 0) {DelayShake(); while (P1_5 == 0); DelayShake(); return 10;}
    if (P1_4 == 0) {DelayShake(); while (P1_4 == 0); DelayShake(); return 14;}
    //第3列=0
    P1 = 0xFF; //TODO 能否不全置1, 而替换成: P1_3 = 0; ??????
    P1_1 = 0;
    if (P1_7 == 0) {DelayShake(); while (P1_7 == 0); DelayShake(); return 3;}
    if (P1_6 == 0) {DelayShake(); while (P1_6 == 0); DelayShake(); return 7;}
    if (P1_5 == 0) {DelayShake(); while (P1_5 == 0); DelayShake(); return 11;}
    if (P1_4 == 0) {DelayShake(); while (P1_4 == 0); DelayShake(); return 15;}
    //第4列=0
    P1 = 0xFF; //TODO 能否不全置1, 而替换成: P1_3 = 0; ??????
    P1_0 = 0;
    if (P1_7 == 0) {DelayShake(); while (P1_7 == 0); DelayShake(); return 4;}
    if (P1_6 == 0) {DelayShake(); while (P1_6 == 0); DelayShake(); return 8;}
    if (P1_5 == 0) {DelayShake(); while (P1_5 == 0); DelayShake(); return 12;}
    if (P1_4 == 0) {DelayShake(); while (P1_4 == 0); DelayShake(); return 16;}
    return 0;
}